/***
 * * PROJECT
 * *    Logical Neighborhoods - J2ME Run-Time Support
 * * VERSION
 * *    $LastChangedRevision: 118 $
 * * DATE
 * *    $LastChangedDate: 2008-05-28 19:35:12 +0200 (Wed, 28 May 2008) $
 * * LAST_CHANGE_BY
 * *    $LastChangedBy: lmottola $
 * *
 * *    $Id: DatagramObjectIO.java 118 2008-05-28 17:35:12Z lmottola $
 * *
 * *   Logical Neighborhoods -
 * *                   Programming Wireless Sensor Networks
 * *                   (One Slice at a Time)
 * *
 * *   This program is free software; you can redistribute it and/or
 * *   modify it under the terms of the GNU Lesser General Public License
 * *   as published by the Free Software Foundation; either version 2.1
 * *   of the License, or (at your option) any later version.
 * *
 * *   This program is distributed in the hope that it will be useful,
 * *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * *   GNU General Public License for more details.
 * *
 * *   You should have received a copy of the GNU Lesser General Public
 * *   License along with this program; if not, you may find a copy at
 * *   the FSF web site at 'www.gnu.org' or 'www.fsf.org', or you may
 * *   write to the Free Software Foundation, Inc., 59 Temple
 * *   Place - Suite 330, Boston, MA  02111-1307, USA
 ***/

package atag.runtime.ln;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

//import javax.microedition.io.Connector;
//import javax.microedition.io.Datagram;
//import javax.microedition.io.DatagramConnection;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import atag.runtime.ln.messages.LNMessage;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//import com.sun.spot.io.j2me.radiogram.RadiogramConnection;

/**
 * This class provides methods for sending and receiving objects using UDP
 * datagrams. Objects serialization is carried out using suitable
 * ByteInputStream and ByteOutputStream objects.
 *
 * @author Luca Mottola <a
 *         href="mailto:mottola@elet.polimi.it">mottola@elet.polimi.it</a>
 *
 */
public class IPInterfaceIO implements Runnable, Interface {

	private boolean running;

	private DatagramSocket bcastConn;

	private DatagramSocket recvConn;

	private LNMessageListener receiver;

    private int port;
    //the IPs below are going to be set in the constructor.
    private String ip[];

    private int interfaceId;

    public final static int MAX_PACKET_SIZE = 65507;
    byte[] buffer = new byte[MAX_PACKET_SIZE];

	/**
	 * Build a new object for sending and receiving objects via UDP datagrams.
	 *
	 * @param port
	 *            the port at which we are going to receive UPD datagrams.
	 * @param bufferSize
	 *            the size of the receiver buffer.
	 * @param timeout
	 *            a timeout for receiving UDP datagrams.
	 */
	public IPInterfaceIO(int port, LNMessageListener receiver, int interfaceId, String ip[]) {

        this.port=port;

        this.ip = ip;
		this.running = false;
		this.receiver = receiver;
        this.interfaceId = interfaceId;
		try {
            //the 2 port numbers should be same
			this.recvConn = new DatagramSocket(port);
            this.bcastConn = new DatagramSocket();
			//this.bcastConn = new Socket(ip,port);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
            System.out.println("stack trace printed");
		}
	}
    /*private void initbcastConn(int port)
    {
        try {

            this.bcastConn = new Socket(ip, port);
            System.out.println("connected to server"+bcastConn.getRemoteSocketAddress());
        } catch (UnknownHostException ex) {
            Logger.getLogger(IPInterfaceIO.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(IPInterfaceIO.class.getName()).log(Level.SEVERE, null, ex);
        }
    }*/

	public void start() {
		running = true;
		new Thread(this).start();
	}

	/**
	 * Send an object to the Ipv4 local broadcast address. The receiver host has
	 * to wait for incoming objects at the same port as the local
	 * DatagramObjectIO object.
	 *
	 * @param obj
	 *            the object that gets sent.
	 */
	public void sendBroadcastObject(LNMessage obj) {

		try {
			ByteArrayOutputStream data=new ByteArrayOutputStream();
            DataOutputStream dg=new DataOutputStream(data);

			dg = (DataOutputStream)obj.serialize(dg);
            byte message[] = new byte[MAX_PACKET_SIZE];
            for (int i = 0; i < ip.length; i++)
            {
                if(ip[i]==null || ip[i].equals("0.0.0.0"))
                    continue;
                InetAddress  address = InetAddress.getByName(ip[i]);
                DatagramPacket packet = new DatagramPacket(message, message.length,
                                address, port);
                ByteArrayOutputStream bout = new ByteArrayOutputStream();

                packet.setData(data.toByteArray());
                bcastConn.send(packet);
             }
            
                InetAddress  address = InetAddress.getByName("255.255.255.255");
                DatagramPacket packet = new DatagramPacket(message, message.length,
                                address, port);
                ByteArrayOutputStream bout = new ByteArrayOutputStream();

                packet.setData(data.toByteArray());
                bcastConn.send(packet);
             System.out.print("sent");


		} catch (IOException e) {
			//e.printStackTrace();
		}
	}

	/**
	 * Send the object o to the the specified Ipv4 address. The receiver host
	 * has to wait for incoming objects at the same port as the local
	 * DatagramObjectIO object.
	 *
	 * @param obj
	 *            the objects that gets sent.
	 * @param hostAddress
	 *            the IPv4 address of the intended receiver.
	 */
	public void sendObject(LNMessage obj, String destination) {
		// TODO:
	}

	/**
	 * Receive an object at the local port specified at the creation of the
	 * object.
	 *
	 * @return the object received.
	 */
	private LNMessage receiveObject() {

		byte[] recvDg = new byte[600];
		try {
			/*recvDg = recvConn.newDatagram(recvConn.getMaximumLength());
			recvConn.receive(recvDg);
			return LNMessage.deserialize(recvDg);*/
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            recvConn.receive(packet);
            recvDg = packet.getData();

            ByteArrayInputStream bos=new ByteArrayInputStream(recvDg);
            DataInputStream din=new DataInputStream(bos);

            //s.close();

            return LNMessage.deserialize(din);

		} catch (IOException e) {
			//e.printStackTrace();
		}
		return null;
	}

	public void run() {
		while (running) {
			receiver.messageReceived(receiveObject(), this.interfaceId);
		}
	}

	public void stop() {
		running = false;
	}

}

